data segment
	STACK_LENGTH 		EQU 80h
	WordPixelWidth 		EQU 8
	WordPixelHeight 	EQU 8

	MouseX 				dw 0
	MouseY 				dw 0
	
	MouseCol 			db 0
	MouseRow 			db 0

	MouseLeftPressed 	db 0
	MouseRightPressed 	db 0

	DELAY 				dw 0FFF0h
	RandomSeed     		dw 1234h

	GameBoardStrWidth  	EQU 44
	GameBoardStrHeight 	EQU 22
	GameBoardStr		db '   | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10|'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 1 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 2 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 3 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 4 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 5 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 6 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 7 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 8 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 9 | # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'
						db ' 10| # | # | # | # | # | # | # | # | # | # |'
						db '---+---+---+---+---+---+---+---+---+---+---+'

	GameBoardWidth 		EQU 10
	GameBoardHeight 	EQU 10

	GameBoardData		db 0,41h,0,0,41h,0,0,0,0,0
						db 0,0,0,0,0,0,0,41h,0,0
						db 0,0,0,41h,41h,41h,0,0,0,0
						db 0,41h,0,0,0,0,0,0,0,0
						db 0,0,0,0,41h,0,0,0,0,0
						db 0,0,0,0,0,0,0,0,0,0
						db 0,0,0,0,0,41h,0,0,41h,0
						db 0,0,0,0,0,0,0,0,0,0
						db 0,0,41h,0,0,41h,0,0,0,0
						db 41h,0,0,0,0,0,0,0,0,0
	
	GameBoardUncover	db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1
						db 1,1,1,1,1,1,1,1,1,1

	
	GameButtonStrHeight 	EQU 3
	GameButtonStrWidth		EQU 13
	GameButtonRestartStrRow EQU 0
	GameButtonRestartStrCol EQU 45

	GameButtonRestarStr		db '+-----------+'
							db '|  RESTART  |'
							db '+-----------+'

	GameButtonExitStrRow 	EQU 3
	GameButtonExitStrCol 	EQU 45

	GameButtonExitStr		db '+-----------+'
							db '| EXIT GAME |'
							db '+-----------+'


	GameUIStrRow 	EQU 8
	GameUIStrCol 	EQU 45
	GameUIStrWidth	EQU 13
	GameUIStrHeight EQU 7

	GameUIStr 		db '+-----------+'
					db '| MINES: 00 |'
					db '|           |'
					db '| TIME:000S |'
					db '+--+-----+--+'
					db '   | ^_^ |   '
					db '   +-----+   '

	GameWinDieWidth		EQU 23
	GameWinDieHeight 	EQU 5
	GameWinDieStrRow 	EQU 17
	GameWinDieStrCol   	EQU 45

	GameWinStr 			db ' __        ___       _ '
						db ' \ \      / (_)_ __ | |'
						db '  \ \ /\ / /| |  _ \| |'
						db '   \ V  V / | | | | |_|'
						db '    \_/\_/  |_|_| |_(_)'

	GameDieStr 			db '   ____ ___ _____ _    '
						db '  |  _ \_ _| ____| |   '
						db '  | | | | ||  _| | |   '
						db '  | |_| | || |___|_|   '
						db '  |____/___|_____(_)   '


	GameStatus 	db 0
	SignNum 	db 0

	TempX 	dw 0
	TempY 	dw 0
	TempZ 	dw 0
	TempI 	dw 0
	TempJ 	dw 0
	TempK 	dw 0
	TempX1 	dw 0
	TempX2 	dw 0
	TempY1 	dw 0
	TempY2 	dw 0
	TempStr db 32 dup (0)

	UseTimeStartTicks 	dw 0
	GameMinesCounts 	EQU 15
data ends

stack segment stack
	DB STACK_LENGTH DUP (0)
stack ends

code segment
	assume ds:data,cs:code,ss:stack

	delayExeute:
		mov cx,DELAY
		delayExeute_loop:
		loop delayExeute_loop
		ret
	
	; Xorshift 随机数生成器
	generateRandom:
		mov ax, RandomSeed     	; 加载当前种子到 AX
		mov dx, ax             	; 复制种子到 DX
		mov cl,7
		shl ax, cl              ; 左移 7 位
		xor ax, dx             	; ax = ax 异或 DX
		mov dx, ax             	; 复制到 dx

		mov cl,9
		shr ax, cl              ; 右移 9 位
		xor ax, dx             	; ax = ax 异或 DX
		mov dx, ax             	; 复制到 DX
		mov cl,13

		shl ax, cl             	; 左移 13 位
		xor ax, dx             	; ax = ax 异或 DX
		mov RandomSeed, AX     	; 将新的伪随机数存回种子
		ret

	; 生成指定范围的随机数
	; 输入：bx=最大值，cx=最小值，dx=输出结果
	randomInRange:
		sub bx, cx				; 范围值bx = 最大值 - 最小值
		push bx					; 保持范围值
		push cx					; 保存最小值
		call generateRandom		; 生成伪随机数并更新随机种子
		pop cx
		pop bx

		xor dx, dx				; 清空dx
		mov ax,RandomSeed		; 加载随机种子
		div bx					; ax = ax / bx, dx = dx % bx
		add dx, cx				; dx = (dx + 最小值)
		RET
	
	; 在指定行列号显示一个字符
	; 输入：bx=行号，cx=列号 dx=字符值
	putChar:
		; 偏移地址 = (行号 × 160) + (列号 × 2)
		mov ax,160
        mul bl
		add cx,cx
        add ax,cx
        mov di,ax
        mov es:[di],dx	; 写入显存
		ret
	
	; 获取指定行列号的字符值
	; 输入：bx=行号，cx=列号 输出dx=字符值
	getPositionChar:
		mov ax,160
        mul bl
		add cx,cx
        add ax,cx
        mov di,ax
		mov dx,es:[di]
		ret
	
	; 在指定行列号处绘制一个二维字符串
	; 输入：TempY1=起始行号，TempX1=起始列号，TempY2=字符串高度，TempX2=字符串宽度，bx=字符串偏移地址，dh=字符颜色，
	drawString:
		mov ax,TempY1
		add TempY2,ax
		mov ax,TempX1
		add TempX2,ax

		mov TempZ,0
		mov TempJ,bx
		mov dl,0
		mov TempK,dx

		drawString_if1:
		mov ax,TempY1
		cmp ax,TempY2
		je drawString_end
		mov si,TempX1

		drawString_if2:
		cmp si,TempX2
		je drawString_s1
		
		mov di,TempZ
		mov bx,TempJ
		mov dx,TempK
		mov dl,ds:[bx+di]
		mov bx,TempY1
		mov cx,si
		call putChar
		inc TempZ
		inc si
		jmp drawString_if2

		drawString_s1:
		inc TempY1
		jmp drawString_if1

		drawString_end:
		ret

	getMouseInfo:
		mov ax,3
		int 33h
		mov MouseX, cx				; 鼠标的 X 坐标（水平像素位置）
		mov MouseY, dx				; 鼠标的 Y 坐标（垂直像素位置）
		; 检测鼠标左键
		test bl,1				 	; 第0位：左键是否按下（1 = 按下）
		jz getMouseInfo_s1
		mov MouseLeftPressed,1
		jmp getMouseInfo_s2
		getMouseInfo_s1:
		mov MouseLeftPressed,0
		; 检测鼠标右键
		getMouseInfo_s2:
		test bl,2					; 第1位：右键是否按下（1 = 按下）
		jz getMouseInfo_s3
		mov MouseRightPressed,1
		jmp getMouseInfo_end
		getMouseInfo_s3:
		mov MouseRightPressed,0
		getMouseInfo_end:
		ret
	
	; 获取当前鼠标所在行号列号
	getMouseRC:
        call getMouseInfo
        mov ax,MouseX
        mov bl,WordPixelWidth
        div bl
        mov MouseCol,al
        mov ax,MouseY
        mov bl,WordPixelHeight
        div bl
        mov MouseRow,al
        ret
	
	; 根据行列号获取GameBoardData索引号
	; 输入：bx=行号，cx=列号 输出：si=索引值
	getBoardMemIndex:
		mov ah,0
		mov al,GameBoardWidth
		mul bl
		add ax,cx
		mov si,ax
		ret

	; 根据行列号获取GameBoardStr索引号
	; 输入：bx=行号，cx=列号 输出：si=索引值
	getBoardStrMemIndex:
		mov ah,0
		mov al,GameBoardStrWidth
		mul bl
		add ax,cx
		mov si,ax
		ret
	
	; 随机布雷
	randomSetMines:
		mov ah,0
		mov al,GameMinesCounts
		mov TempX,ax

		setMines_if1:
		cmp TempX,0						; 判断未布雷数值是否为0
		je endSetMines					; 为0，则结束随机布雷

		mov cx,0
		mov bx,0
		mov bl,GameBoardHeight
		call randomInRange
		mov si,dx						; 获取随机行号

		mov cx,0
		mov bx,0
		mov bl,GameBoardWidth
		call randomInRange
		mov di,dx						; 获取随机列号

		mov bx,si
		mov cx,di
		call getBoardMemIndex			; 获取GameBoardData索引值

		cmp ds:[GameBoardData+si],41h	; 判断该单元是否已经是雷（41h代表雷）
		je setMines_if1					; 已经是雷，则重新获取行列号

		mov ds:[GameBoardData+si],41h	; 否则设置该单元为雷
		dec TempX						; 未布雷数量值-1
		jmp setMines_if1

		endSetMines:
		ret

	; 计算指定单元周围8格雷的数量
	; 输入：bx=行号，cx=列号
	calcAroundMines:
		mov TempY,bx
		mov TempX,cx
		call getBoardMemIndex		
		cmp ds:[GameBoardData+si],41h	; 判断该单元是否为雷（41h代表雷）
		je calcAroundMines_end			; 为雷，则结束计算

		mov si,TempY
		mov di,TempX

		dec si
		dec di
		mov ax,si
		add ax,2
		mov TempJ,ax

		mov ax,di
		add ax,2
		mov TempK,ax
		mov TempZ,di

		calcAroundMines_if1:
		cmp si,0
		jl calcAroundMines_s1
		cmp si,TempJ
		jg calcAroundMines_end
		mov ax,si
		cmp al,GameBoardHeight
		jge calcAroundMines_end
		mov di,TempZ

			calcAroundMines_if2:
			cmp di,0
			jl calcAroundMines_s2
			cmp di,TempK
			jg calcAroundMines_s1
			mov ax,di
			cmp al,GameBoardWidth
			jge calcAroundMines_s1
			mov bx,si
			mov cx,di
			push si
			call getBoardMemIndex
			mov al,ds:[GameBoardData+si]
			pop si
			cmp al,41h
			jne calcAroundMines_s2		; 不是雷，就进行下一次循环
			mov bx,TempY 
			mov cx,TempX
			push si
			call getBoardMemIndex
			inc ds:[GameBoardData+si]	; 记录雷数加1
			pop si					
			calcAroundMines_s2:
			inc di
			jmp calcAroundMines_if2

		calcAroundMines_s1:
		inc si
		jmp calcAroundMines_if1

		calcAroundMines_end:
		ret

	; 根据数值绘制表情
	; 输入bl=表情号码
	drawExpression:
		mov TempY1,GameUIStrRow
		add TempY1,5
		mov TempX1,GameUIStrCol
		add TempX1,5
		mov TempY2,1
		mov TempX2,3

		cmp bl,0
		je drawExpression_s1
		cmp bl,1
		je drawExpression_s2
		cmp bl,2
		je drawExpression_s3
		cmp bl,3
		je drawExpression_s4
		cmp bl,41h
		je drawExpression_s5
		cmp bl,0FFh
		je drawExpression_s6

		mov TempStr[0],'Q'
		mov TempStr[1],'_'
		mov TempStr[2],'Q'
		mov dh,0Fh
		jmp drawExpression_end

		drawExpression_s1:
		mov TempStr[0],'>'
		mov TempStr[1],'_'
		mov TempStr[2],'<'
		mov dh,0Fh
		jmp drawExpression_end

		drawExpression_s2:
		mov TempStr[0],'o'
		mov TempStr[1],'_'
		mov TempStr[2],'o'
		mov dh,0Fh
		jmp drawExpression_end

		drawExpression_s3:
		mov TempStr[0],'o'
		mov TempStr[1],'_'
		mov TempStr[2],'O'
		mov dh,0Fh
		jmp drawExpression_end

		drawExpression_s4:
		mov TempStr[0],'O'
		mov TempStr[1],'_'
		mov TempStr[2],'o'
		mov dh,0Fh
		jmp drawExpression_end

		drawExpression_s5:
		mov TempStr[0],'X'
		mov TempStr[1],'_'
		mov TempStr[2],'X'
		mov dh,0Ch
		jmp drawExpression_end

		drawExpression_s6:
		mov TempStr[0],'?'
		mov TempStr[1],'_'
		mov TempStr[2],'?'
		mov dh,0Fh

		drawExpression_end:
		mov bx, offset TempStr
		call drawString
		ret
	
	; 绘制游戏棋盘
	drawGameBoard:
		mov ax,0
		mov TempY1,0
		mov TempX1,0
		mov al,GameBoardStrHeight
		mov TempY2,ax
		mov al,GameBoardStrWidth
		mov TempX2,ax
		mov bx,offset GameBoardStr
		mov dh,7Fh
		call drawString
		printBoard_end:
		ret

	; 显示指定单元内容
	; 输入bx=行号，cx=列号
	showCell:
		push bx
		push cx
		call getBoardMemIndex
		mov al,ds:[GameBoardData+si]
		cmp al,0			
		jne showCell_s1
		
		mov al,' '			; 数值为0，显示为空
		mov dl,al
		mov dh,7Eh
		jmp showCell_s2

		showCell_s1:
		cmp al,41h			; 如果是雷
		jne showCell_s1_c
		mov dl,'X'
		mov dh,07Ch
		jmp showCell_s2

		showCell_s1_c:
		add al,30h
		mov dl,al
		cmp al,31h
		jne showCell_s1_a
		mov dh,79h
		jmp showCell_s2

		showCell_s1_a:
		cmp al,32h
		jne showCell_s1_b
		mov dh,7Ah
		jmp showCell_s2
		
		showCell_s1_b:
		mov dh,7Eh

		showCell_s2:
		pop cx
		pop bx
		; 数据行列号转换字符画面行列号
		mov ax,bx
		mov bl,2
		mul bl
		add ax,2
		mov bx,ax

		mov ax,cx
		mov cl,4
		mul cl
		add ax,5
		mov cx,ax
		
		call putChar	; 显示单元内容
		ret

	; 更新单元显示状态
	; 鼠标右击后单元为标记，解决左键时鼠标显示与单元的冲突
	updateCellsStatus:
		mov si,0
		showUncoverCells_if1:
		mov ax,si
		cmp al,GameBoardHeight
		je showUncoverCells_end
		mov di,0
		showUncoverCells_if2:
		mov ax,di
		cmp al,GameBoardWidth
		je showUncoverCells_s1
		push si
		mov bx,si
		mov cx,di
		call getBoardMemIndex
		mov dl,ds:[GameBoardUncover+si]
		cmp dl,1
		pop si
		jne	showUncoverCells_as1
		mov bx,si
		mov cx,di
		push si
		push di
		call showCell
		pop di
		pop si
		jmp showUncoverCells_s2
		showUncoverCells_as1:
		cmp dl,2
		jne showUncoverCells_as2

		mov ax,si
		mov bl,2
		mul bl
		add ax,2
		mov bx,ax

		mov ax,di
		mov cl,4
		mul cl
		add ax,5
		mov cx,ax
		mov dl,'?'
		mov dh,0fDh
		push si
		push di
		call putChar
		pop di
		pop si
		jmp showUncoverCells_s2

		showUncoverCells_as2:

		mov ax,si
		mov bl,2
		mul bl
		add ax,2
		mov bx,ax

		mov ax,di
		mov cl,4
		mul cl
		add ax,5
		mov cx,ax
		mov dl,'#'
		mov dh,7Fh
		push si
		push di
		call putChar
		pop di
		pop si

		showUncoverCells_s2:
		inc di
		jmp showUncoverCells_if2

		showUncoverCells_s1:
		inc si
		jmp showUncoverCells_if1
		
		showUncoverCells_end:
		ret

	; 显示所有单元内容
	uncoverAllCells:
		mov ax,0
		mov bx,0
		mov al,GameBoardHeight
		mov bl,GameBoardWidth
		mul bl
		; 显示所有单元内容
		mov cx,ax
		mov si,0
		uncoverAllCells_loop:
		mov GameBoardUncover[si],1
		inc si
		loop uncoverAllCells_loop
		ret
	
	; 揭开指定单元
	; 输入: bx=行号，cx=列号
	uncoverCell:
		cmp bl, 0					
		jl uncoverCell_end					; 行号<0 程序结束
		cmp bl, GameBoardHeight		
		jge uncoverCell_end					; 行号>=棋盘高度 程序结束

		cmp cx, 0					
		jl uncoverCell_end					; 列号<0 程序结束
		cmp cl, GameBoardWidth		
		jge uncoverCell_end					; 列号>=棋盘宽度 程序结束 

		; 检查是否已揭示
		push bx            					; 临时保存行号
		push cx            					; 临时保存列号
		call getBoardMemIndex				; 获取棋盘Data索引值
		pop cx
		pop bx

		cmp ds:[GameBoardUncover+si],1 		; 如果该单元已揭示
		je uncoverCell_end					; 程序结束
		mov ds:[GameBoardUncover+si],1		; 否则设置该单元为：已揭示
		
		push bx
		push cx
		mov bl,ds:[GameBoardData+si]		; 获取棋盘Data对应值
		call drawExpression					; 根据值绘制表情
		pop cx
		pop bx
		
		push bx									
		push cx
		call showCell						; 显示该单元内容
		call delayExeute					; 执行程序延迟（实现动画效果）
		pop cx
		pop bx

		cmp ds:[GameBoardData+si], 0		; 判断该单元记录周围雷数是否为0
		jne uncoverCell_end					; 不为0结束程序

		; 该单元记录雷数不为0，则继续递归揭示周围单元
		mov TempY,bx
		mov TempX,cx
		dec bx
		dec cx
		mov TempY1,bx
		mov TempX1,cx
		add bx,2
		add cx,2
		mov TempY2,bx
		mov TempX2,cx
		mov ax,TempY1
		mov TempY,ax
		mov ax,TempX1
		mov TempX,ax

		uncoverCell_if1:
		mov ax,TempY
		cmp ax,TempY2
		jg uncoverCell_end
		mov ax,TempX1
		mov TempX,ax

		uncoverCell_if2:
		mov ax,TempX
		cmp ax,TempX2
		jg uncoverCell_s1
		push TempX
		push TempY
		push TempX1
		push TempY1
		push TempX2
		push TempY2
		mov bx,TempY
		mov cx,TempX
		call uncoverCell
		pop TempY2
		pop TempX2
		pop TempY1
		pop TempX1
		pop TempY
		pop TempX
		inc TempX
		jmp uncoverCell_if2

		uncoverCell_s1:
		inc TempY
		jmp uncoverCell_if1
	
		uncoverCell_end:
		ret
	
	; 显示游戏棋盘数据（用于Debug测试）
	showGameData:
		mov si,0
		showGameData_f1:
		mov ah,0
		mov al,GameBoardHeight
		cmp si,ax
		je showGameData_end
		mov di,0
		showGameData_f2:
		mov ah,0
		mov al,GameBoardWidth
		cmp di,ax
		je showGameData_s1
		mov bx,si
		mov cx,di
		push si
		call getBoardMemIndex
		mov al,ds:[GameBoardData+si]
		cmp al,41h
		jne showGameData_f2_s1
		mov al,'X'
		mov dh,4Fh
		jmp showGameData_f2_s2
		showGameData_f2_s1:
		add al,30h
		mov dh,0Eh
		showGameData_f2_s2:
		pop si
		push di
		mov bx,si
		add bx,0
		mov cx,di
		add cx,60
		mov dl,al
		call putChar
		pop di
		inc di
		jmp showGameData_f2

		showGameData_s1:
		inc si
		jmp showGameData_f1

		showGameData_end:
		ret
	
	checkMouseOverUIButton:
		; 检测是否悬空在Restart按钮上
		mov al,GameButtonRestartStrRow
		cmp MouseRow,al
		jnae mouseInRestartButton_s1
		add al,GameButtonStrHeight
		dec al
		cmp MouseRow,al
		jnbe mouseInRestartButton_s1
		mov al,GameButtonRestartStrCol
		cmp MouseCol,al
		jnae mouseInRestartButton_s1
		add al,GameButtonStrWidth
		dec al
		cmp MouseCol,al
		jnbe mouseInRestartButton_s1
		mov dl,1
		jmp mouseInRestartButton_s2
		mouseInRestartButton_s1:
		mov dl,0

		; 检测是否悬空在Restart按钮上
		mouseInRestartButton_s2:
		mov al,GameButtonExitStrRow
		cmp MouseRow,al
		jnae mouseInRestartButton_s3
		add al,GameButtonStrHeight
		dec al
		cmp MouseRow,al
		jnbe mouseInRestartButton_s3
		mov al,GameButtonExitStrCol
		cmp MouseCol,al
		jnae mouseInRestartButton_s3
		add al,GameButtonStrWidth
		dec al
		cmp MouseCol,al
		jnbe mouseInRestartButton_s3
		mov dh,1
		jmp heckMouseOverUIButton_end

		mouseInRestartButton_s3:
		mov dh,0
		heckMouseOverUIButton_end:
		ret

	drawGameButton:
		call checkMouseOverUIButton
		cmp dl,1
		je showGameButton_as1
		mov dh,0Eh
		jmp showGameButton_as2
		showGameButton_as1:
		mov dh,7Eh

		showGameButton_as2:
		; 绘制重置按钮
		mov TempY1,GameButtonRestartStrRow
		mov TempX1,GameButtonRestartStrCol
		mov TempY2,GameButtonStrHeight
		mov TempX2,GameButtonStrWidth
		mov bx,offset GameButtonRestarStr
		call drawString

		call checkMouseOverUIButton
		cmp dh,1
		je showGameButton_as3
		mov dh,0Eh
		jmp showGameButton_as4
		showGameButton_as3:
		mov dh,7Eh

		showGameButton_as4:
		; 绘制退出按钮
		mov TempY1,GameButtonExitStrRow
		mov TempX1,GameButtonExitStrCol

		mov TempY2,GameButtonStrHeight
		mov TempX2,GameButtonStrWidth
		mov bx,offset GameButtonExitStr
		call drawString

		showGameButton_end:
		ret
	
	ifGameButtonClicked:
		cmp MouseLeftPressed,1
		jne ifGameButtonClicked_end

		call checkMouseOverUIButton
		cmp dl,1
		jne ifGameButtonClicked_s1
		call drawGameBoard
		call initGameData

		ifGameButtonClicked_s1:
		call checkMouseOverUIButton
		cmp dh,1
		jne ifGameButtonClicked_end
		mov ax,4c00h
		int 21h
		ifGameButtonClicked_end:
		ret
	
	ifGameBoardClicked:
		mov al,MouseLeftPressed
		add al,MouseRightPressed
		cmp al,1
		jnae ifGameBoardClicked_end

		; 判断鼠标位置是否在游戏棋盘内
		mov al,MouseRow
		cmp al,2
		jb ifGameBoardClicked_end
		cmp al,GameBoardStrHeight
		jae ifGameBoardClicked_end

		mov al,MouseCol
		cmp al,5
		jb ifGameBoardClicked_end
		cmp al,GameBoardStrWidth
		jae ifGameBoardClicked_end

		; 判断鼠标位置是否为棋盘数据所映射的字符位置
		mov bh,0
		mov ch,0
		mov bl,MouseRow
		mov cl,MouseCol
		
		sub bx,2
		mov ax,bx
		mov bl,2
		div bl
		cmp ah,0						;根据余数判断是否位置正确
		jne ifGameBoardClicked_end
		mov bl,al

		sub cx,5
		mov ax,cx
		mov cl,4
		div cl
		cmp ah,0						;根据余数判断是否位置正确
		jne ifGameBoardClicked_end
		mov cl,al

		cmp GameStatus,0				; 当前是否开始游戏
		jne ifGameBoardClicked_bs1		; 已经开始则跳转

		mov GameStatus,1				; 开始游戏
		mov ah, 00h						; 获取游戏开始时的Tick值
		int 1Ah             		
		mov UseTimeStartTicks, dx 		; 保存当前Tick值

		ifGameBoardClicked_bs1:
		cmp MouseRightPressed,1			; 判断是否为鼠标右击
		jne ifGameBoardClicked_s1		; 否则执行鼠标左击程序
		call getBoardMemIndex

		cmp GameBoardUncover[si],1		; 判断该单元是否揭开状态
		je ifGameBoardClicked_end		; 揭开则结束程序

		cmp GameBoardUncover[si],2		; 否则判断该单元是否被标记
		je  ifGameBoardClicked_as1_a	; 已经标记则跳转执行取消标记程序

		mov GameBoardUncover[si],2		; 没有标记则标记
		inc SignNum						; 标记数+1
		mov bl,0FFh						; 设置表情号
		call drawExpression				; 显示思考表情
		
		ifGameBoardClicked_as1_a_loop1:	; 等待鼠标松开
		call getMouseInfo
		cmp MouseRightPressed,1
		je ifGameBoardClicked_as1_a_loop1
		jmp ifGameBoardClicked_end		; 结束程序

		ifGameBoardClicked_as1_a:		
		mov GameBoardUncover[si],0		; 取消标记
		dec SignNum						; 标记数-1
		
		ifGameBoardClicked_as1_a_loop2:	; 等待鼠标松开
		call getMouseInfo
		cmp MouseRightPressed,1
		je ifGameBoardClicked_as1_a_loop2
		jmp ifGameBoardClicked_end

		; 鼠标左键操作
		ifGameBoardClicked_s1:
		call getBoardMemIndex
		cmp GameBoardData[si],41h		; 判断该单元是否为雷
		jne ifGameBoardClicked_as2_a	; 不是则跳转
		mov bl,41h
		call drawExpression				; 显示死亡表情
		call uncoverAllCells
		mov GameStatus,2				; 设置游戏状态为死亡

		; 显示死亡图标
		mov TempY1,GameWinDieStrRow
		mov TempX1,GameWinDieStrCol
		mov TempY2,GameWinDieHeight
		mov TempX2,GameWinDieWidth
		mov bx,offset GameDieStr
		mov dh,8ch
		call drawString
		jmp ifGameBoardClicked_end

		ifGameBoardClicked_as2_a:
		call uncoverCell				; 递归揭开该单元及其周围单元
		ifGameBoardClicked_end:
		ret

	initGameData:
		mov GameStatus,0		
		mov UseTimeStartTicks,0
		mov SignNum,0

		mov ax,0
		mov bx,0
		mov al,GameBoardHeight
		mov bl,GameBoardWidth
		mul bl
		mov cx,ax
		mov si,0
		initGameData_loop1:
		mov GameBoardUncover[si],0
		inc si
		loop initGameData_loop1

		mov cx,ax
		mov si,0
		initGameData_loop2:
		mov GameBoardData[si],0
		inc si
		loop initGameData_loop2
		
		call randomSetMines
		call clearWinDieStr

		mov bl,0
		call drawExpression

		mov TempY2,0
		initGameData_if1:
		mov ax,TempY2
		cmp al,GameBoardHeight
		je initGameData_end
		mov TempX2,0
		initGameData_if2:
		mov ax,TempX2
		cmp al,GameBoardWidth
		je initGameData_s1
		mov bx,TempY2
		mov cx,TempX2
		call calcAroundMines
		inc TempX2
		jmp initGameData_if2
		initGameData_s1:
		inc TempY2
		jmp initGameData_if1

		initGameData_end:
		ret
	
	clearWinDieStr:
		mov TempY2,0
		clearWinDieStr_if1:
		mov ax,TempY2
		cmp al,GameWinDieHeight
		je clearWinDieStr_end
		mov TempX2,0
		clearWinDieStr_if2:
		mov ax,TempX2
		cmp al,GameWinDieWidth
		je clearWinDieStr_s1
		mov bx,TempY2
		mov cx,TempX2
		add bx,GameWinDieStrRow
		add cx,GameWinDieStrCol
		mov dx,0
		call putChar
		inc TempX2
		jmp clearWinDieStr_if2
		clearWinDieStr_s1:
		inc TempY2
		jmp clearWinDieStr_if1
		clearWinDieStr_end:
		ret

	drawGameUI:
		mov TempY1,GameUIStrRow
		mov TempX1,GameUIStrCol
		mov TempY2,GameUIStrHeight
		mov TempX2,GameUIStrWidth
		mov bx,offset GameUIStr
		mov dh,0Bh
		call drawString			; 绘制游戏UI
		ret

	updateGameUI:
		cmp GameStatus,1		; 游戏是否开始
		jne drawUsedTime_end

		; 获取当前Tick值
		mov ah, 00h
		int 1Ah             	
		
		mov ax,UseTimeStartTicks
		sub dx,ax				; 差值为经过的Tick值
		mov ax,dx
		mov dx,0
	    mov bx, 18          	; 每秒18.2次Tick，则除以18约等于经过的秒数
		div bx              	; AX / BX, 商 = 秒

		mov cx,3
		mov si,2
		mov bx,10
		drawUsedTime_loop:
		mov dx,0
		div bx
		add dx,'0'
		mov TempStr[si],dl
		dec si
		loop drawUsedTime_loop

		mov TempY1,GameUIStrRow
		add TempY1,3
		mov TempX1,GameUIStrCol
		add TempX1,7

		mov TempY2,1
		mov TempX2,3
		mov bx,offset TempStr
		mov dh,03h
		call drawString

		mov cx,2
		mov si,1
		mov bx,10
		mov ah,0
		mov al,GameMinesCounts
		sub al,SignNum
		drawUsedTime_loop2:
		mov dx,0
		div bx
		add dx,'0'
		mov TempStr[si],dl
		dec si
		loop drawUsedTime_loop2

		mov TempY1,GameUIStrRow
		add TempY1,1
		mov TempX1,GameUIStrCol
		add TempX1,9

		mov TempY2,1
		mov TempX2,2
		mov bx,offset TempStr
		mov dh,03h
		call drawString

		drawUsedTime_end:
		ret

	checkWon:
		cmp GameStatus,1
		jne checkWon_end

		mov ax,0
		mov bx,0
		mov al,GameBoardHeight
		mov bl,GameBoardWidth
		mul bl

		mov cx,ax
		mov si,0
		mov di,0
		checkWon_loop1:
		cmp GameBoardUncover[si],1
		jne checkWon_loop1_s1
		inc di
		checkWon_loop1_s1:
		inc si
		loop checkWon_loop1

		sub ax,di
		cmp al,GameMinesCounts
		jne checkWon_end
		
		call uncoverAllCells		; 显示所有单元内容
		
		mov GameStatus,3			; 设置游戏状态为胜利
		; 显示胜利图标
		mov TempY1,GameWinDieStrRow
		mov TempX1,GameWinDieStrCol
		mov TempY2,GameWinDieHeight
		mov TempX2,GameWinDieWidth
		mov bx,offset GameWinStr
		mov dh,8Ah
		call drawString
		checkWon_end:
		ret

	main:
    	mov ax,data
		mov ds,ax					; 初始化数据段地址

		mov ax, stack		
		mov ss, ax					; 初始化栈段地址
		mov sp, STACK_LENGTH		; 设置栈指针到栈顶

        mov ax, 0003h  				; 设置 80×25 文本模式
        int 10h        			

		mov ax,0					; 初始化鼠标
		int 33h
		cmp ax,0
		je exit						; 结束程序

		mov ax,0B800h
		mov es,ax					; 初始化显存段地址
   		
		mov ah, 01h     		
		mov ch, 20h     		
		mov cl, 0       		
		int 10h      				; 隐藏光标

		call drawGameBoard			; 绘制游戏棋盘
		call drawGameUI				; 绘制游戏UI
		call initGameData			; 初始化游戏数据

    gameLoop:
	    mov ax, 1					; 显示当前鼠标位置
    	int 33h
		call showGameData			; 显示棋盘数据（用于Debug）

		call getMouseRC				; 获取当前鼠标所在字符行列号
		call ifGameButtonClicked	; 检测鼠标点击UI按钮
		call drawGameButton			; 绘制按钮UI
		call updateCellsStatus		; 更新当前棋盘单元显示状态

		cmp GameStatus,2			
		je gameLoop
		cmp GameStatus,3
		je gameLoop

		call ifGameBoardClicked		; 检测鼠标对棋盘的操作
		call updateGameUI			; 更新UI显示的数据
		call checkWon				; 游戏胜利判断
        jmp gameLoop
    exit:
        mov ax,4c00h
        int 21h
code ends
end main